component-js@1 - Auto-load web-components from extensions - #34325
Conversation
|
🤖 Thank you for contributing to CiviCRM! ❤️ We will need to test and review this PR. 👷 Introduction for new contributors...
Quick links for reviewers...
|
|
This is very very cool @totten ! Won't get to testing until after the break but very very keen on the principle. |
| ############################################################################### | ||
| ## Below, we stop executing PHP. The rest of the file contains the template | ||
| ## for "component.js". |
There was a problem hiding this comment.
why can't this be in a separate file?
There was a problem hiding this comment.
Mixin backports/versioning are generally based on one-file/one-mixin.
From POV of civicrm-core and PHP interpreter, I suppose one could do more files. But it’s definitely messier on civix side. I’d probably want to have a few more needs before biting off that task
| /** | ||
| * @return string | ||
| */ | ||
| private function getTemplate(): string { | ||
| $fp = fopen(__FILE__, 'r'); | ||
| fseek($fp, __COMPILER_HALT_OFFSET__); | ||
| $template = stream_get_contents($fp); | ||
| fclose($fp); | ||
| return $template; | ||
| } |
There was a problem hiding this comment.
Fun fact… we actually use __HALT_COMPILER stuff for composer.phar, phpunit.phar, drush.phar, ad nauseam. That’s how you get a CLI executable (top part) combined with an archive (bottom part). You just don’t see it :)
But this is essentially aesthetic. It could use a <<<HEREDOC or a $buffer instead. I thought the payload looked easier to read at the bottom (without extra indentation or escaping stuff).
There was a problem hiding this comment.
I would have just expected it in a separate file. I guess it's tightly bundled and unlikely to need much development, so I don't mind much, but yes aesthetically it seems a bit over-clever to me.
(Ah sorry read the other response about work to support multiple files. Fair enough I guess)
|
One thought: it might be nice to be able to fetch a |
| }); | ||
| } | ||
|
|
||
| $(()=>{ |
There was a problem hiding this comment.
It might not be needed. My thinking was to defer init until page-start so that the downstream files wouldn’t need to. (Huge portions of Civi JS do this - as a way of saying, “Don’t do anything until all our little addons for jQuery+CRM are registered.”)
Of course, theoretically, the component.js is loading in a mid/late part of coreResources (so a fair amount is already preloaded). And/or, the deferral could be done with vanilla JS.
In aggregate, pages might perform better if this part doesn’t try to constrain load-order. But I think it will put the onus on downstream files to think more about ordering.
Aside: When using ESM, the static imports have to be in the top-level of each file; ESM has a certain load-ordering concept. But stuff coming from CRM.* has a different load-ordering concept. Aesthetically, the downstream ESMs can look a bit messier if they have to abide both — e.g. first you do all your imports at top-level; and if you also use CRM.*, then you wrap your main logic in a deferred function. We could get used to that. (God bless hedonic adaptation…)
There was a problem hiding this comment.
Reading a bit more about modules, it turns out that addModule() (aka <script type=module>) has loading rules very similar to $(function...), so the jQuery isn't doing much.
I believe that Chrome allows ESM’s to load CSS modules. Alas, Firefox doesn’t. So if we wanted to use that exact notation, then we would need to use the newer shim. Or define a different (and portable) notation for loading CSS modules. (It’s probably not too hard? Would be nice to preserve compat w/import-maps. Might want to look at how polyfill works on Firefox. Maybe something with |
I was thinking something like:
|
0cbe8e2 to
cecd2b0
Compare
I've been playing around with this today... and there are a few angles...
|
|
FWIW I wouldn't complicate this with bundling. For most cases, Http3 gives us decent performance with separate requests; and if a given extension has many many components, it is likely the extension author can do better with a non-generic solution. Also there are costs in terms of reduced scrutability of console errors; and it generally being a prod/dev divergence, leading to missed bugs. |
Yeah, The performance+availability of HTTP/3 (versus bundling) is an empirical question that can be deferred. IMHO, the main thing is that we have this mapping (
OK, it's nice to have a convention; and it's not hard to implement something along those lines (basically, To my way of reading, it would be tidier with the Timing-wise, it does make sense to address CSS now -- it affects the shape of the hook-data (i.e. Just playing with some of names/phrases for this functionality ("web components", "custom elements", etc):
After looking at that rundown,
|
|
Closing in favor of #34348. |
Overview
Define a file-naming convention for WebComponents (
*.jsor*.mjs) implemented within CiviCRM. Implement lazy-loading with ECMAScript module (ESM) support.ping @ufundo @colemanw
Technical Details: Consumers
As a consumer of a WebComponent, you simply use the tag... somewhere. It can be Quickform or AngularJS or jQuery or whatever. For example:
But how is this new tag defined?
Technical Details: Providers
As the provider of a WebComponent, you will do the following:
info.xmland enable<mixin>component-js@1</mixin>.js/component/TAG-NAME.js.For example, here is an implementation of
<hello-world>:Since this supports ECMAScript modules, you can import helpers from other files. Untested examples:
This is implemented as a mixin, and it should be amenable for backporting on 5.63+.
Comments
The general approach is this:
AssetBuilderto create a semi-static file,component.js, which stores an index of all these WebComponents.MutationObserverto determine when new components are needed.MutationObservershared by all these WebComponents.Limitations worth considering:
es-module-shimswith virtual sources or else php es6 bundler.import()d JS files.